package org.apereo.cas.authentication;

import java.security.GeneralSecurityException;
import java.util.List;

import javax.security.auth.login.FailedLoginException;
import javax.servlet.http.HttpServletRequest;

import org.apereo.cas.authentication.credential.RememberMeUsernamePasswordCredential;
import org.apereo.cas.authentication.metadata.BasicCredentialMetaData;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.web.support.WebUtils;
import org.apereo.cas.web.y9.service.SaveLoginInfoService;
import org.apereo.cas.web.y9.util.Y9Context;
import org.apereo.cas.web.y9.util.Y9MessageDigest;
import org.apereo.cas.web.y9.util.common.Base64Util;
import org.apereo.cas.web.y9.y9user.Y9User;
import org.apereo.cas.web.y9.y9user.Y9UserDao;
import org.springframework.dao.DataAccessException;
import org.springframework.util.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RiseAuthenticationHandler extends AbstractAuthenticationHandler {

    private Y9UserDao y9UserDao;
    private SaveLoginInfoService saveLoginInfoService;

    public RiseAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
        super(name, servicesManager, principalFactory, order);
    }

    @Override
    public AuthenticationHandlerExecutionResult authenticate(Credential credential) throws GeneralSecurityException, PreventedException {
        if (y9UserDao == null) {
            y9UserDao = Y9Context.getBean(Y9UserDao.class);
            saveLoginInfoService = Y9Context.getBean(SaveLoginInfoService.class);
        }

        RememberMeUsernamePasswordCredential riseCredential = (RememberMeUsernamePasswordCredential)credential;
        String loginType = riseCredential.getLoginType();
        String tenantShortName = riseCredential.getTenantShortName();
        String deptId = riseCredential.getDeptId();
        String username = riseCredential.getUsername();
        String password = riseCredential.getPassword();
        String hashed = null;

        String oldtenantname = tenantShortName;
        String oldusername = username;

        String agentTenantShortName = "operation";
        List<Y9User> users = null;
        try {
            username = Base64Util.decode(username, "Unicode");
            password = Base64Util.decode(password, "Unicode");
            if (username.contains("&")) {
                oldusername = username;
                String agentUserName = username.substring(username.indexOf("&") + 1, username.length());
                username = agentUserName;
                tenantShortName = agentTenantShortName;

                if (StringUtils.hasText(deptId)) {
                    users = y9UserDao.findByTenantShortNameAndMobileAndParentId(agentTenantShortName, agentUserName, deptId);
                } else {
                    users = y9UserDao.findByTenantShortNameAndLoginNameAndOriginal(agentTenantShortName, agentUserName, Boolean.TRUE);
                }
                if (users == null || users.isEmpty()) {
                    throw new FailedLoginException("没有找到这个【代理】用户。");
                }
            }
            riseCredential.setUsername(username);
            riseCredential.setPassword(password);

            HttpServletRequest request = WebUtils.getHttpServletRequestFromExternalWebflowContext();
            if (null != request) {
                String systemName = request.getParameter("systemName");
                if (StringUtils.hasText(systemName)) {
                    riseCredential.setSystemName(systemName);
                }
                riseCredential.setUserAgent(request.getHeader("User-Agent"));
                riseCredential.setClientIp(Y9Context.getIpAddr(request));
            }
        } catch (Exception e) {
            throw new FailedLoginException(e.getMessage());
        }

        try {
            if ("mobile".equals(loginType)) {
                if (StringUtils.hasText(deptId)) {
                    users = y9UserDao.findByTenantShortNameAndMobileAndParentId(tenantShortName, username, deptId);
                } else {
                    users = y9UserDao.findByTenantShortNameAndMobileAndOriginal(tenantShortName, username, Boolean.TRUE);
                }
            } else {
                if (StringUtils.hasText(deptId)) {
                    users = y9UserDao.findByTenantShortNameAndLoginNameAndParentId(tenantShortName, username, deptId);
                } else {
                    users = y9UserDao.findByTenantShortNameAndLoginNameAndOriginal(tenantShortName, username, Boolean.TRUE);
                }
            }

            if (users != null && !users.isEmpty()) {
                Y9User y9User = users.get(0);
                hashed = y9User.getPassword();
                if (!Y9MessageDigest.checkpw(password, hashed)) {
                    throw new FailedLoginException("密码错误。");
                }
                if (oldusername.contains("&")) {
                    username = oldusername.substring(0, oldusername.indexOf("&"));
                    riseCredential.setUsername(username);
                    riseCredential.setTenantShortName(oldtenantname);
                }

                try {
                    saveLoginInfoService.SaveLoginInfo(riseCredential, "true", "登录成功");
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }

                AuthenticationHandlerExecutionResult hr = new DefaultAuthenticationHandlerExecutionResult(this, new BasicCredentialMetaData(riseCredential), principalFactory.createPrincipal(username));
                return hr;
            } else {
                throw new FailedLoginException("没有找到这个用户。");
            }
        } catch (DataAccessException e) {
            throw new FailedLoginException(e.getMessage());
        }
    }

    @Override
    public boolean supports(Class<? extends Credential> clazz) {
        return RememberMeUsernamePasswordCredential.class.isAssignableFrom(clazz);
    }

    @Override
    public boolean supports(final Credential credential) {
        boolean b = credential instanceof RememberMeUsernamePasswordCredential;
        return b;
    }

}
